import Event from '../Event';

interface PluginManagerEvents {
  [PluginManager.EVENT_PLUGINS_LOADED]: (plugins: Partial<Record<keyof typeof PluginRawMap, any>>) => void;
}

export const PluginRawMap = {
  PlantAreaManager: () => import('../PlantAreaManager/index'),
  DeviceManager: () => import('../DeviceManager/index'),
  RoadManager: () => import('../Field/RoadManager/index'),
} as const;

/** 未pick的属性由对应的类内部传递
 *  - 每次修改需要在所有new GreenHouse 和 Field的地方对应修改
 *  - @see Editor.SpaceAssembler.addGreenHouse
 *  - @see Editor.SpaceAssembler.addField
 */
export type PluginOptionMap = {
  PlantAreaManager: Pick<Editor.PlantAreaManagerOption, 'camera' | 'preloadCropPlotRawDatas' | 'preloadCropRackRawDatas'>;
  DeviceManager: Pick<Editor.DeviceManagerOption, 'camera' | 'preloadDeviceRawDatas'>;
  // FIXME: RoadManagerOption需要修改
  RoadManager: Editor.RoadManagerOption;
};
3
export type PluginMap = {
  PlantAreaManager: Editor.PlantAreaManager;
  DeviceManager: Editor.DeviceManager;
  RoadManager: Editor.RoadManager;
};

export type Plugins = {
  [K in keyof typeof PluginRawMap]?: PluginMap[K];
};

export type PluginOption = Array<{
  /** 插件名称 PlantAreaManager | DeviceManager | RoadManager */
  name: keyof typeof PluginRawMap;
  /** 插件配置 只需传入pick元素,其余自动推导 */
  option: PluginOptionMap[keyof typeof PluginRawMap];
}>;

export default class PluginManager extends Event<PluginManagerEvents> {
  static EVENT_PLUGINS_LOADED = 'PLUGINS_LOADED';

  public plugins: Plugins = {};

  constructor(option: PluginOption) {
    super();
    this._load(option);
  }

  private async _load(plugins: PluginOption) {
    if (!Array.isArray(plugins) || plugins.length === 0) {
      this._emitEvent(PluginManager.EVENT_PLUGINS_LOADED, this.plugins);
      return;
    }

    try {
      const pluginPromises = plugins.map(async <K extends keyof typeof PluginRawMap>(pluginOption: { name: K; option: PluginOptionMap[K] }) => {
        const { name: pluginName, option } = pluginOption;
        const pluginModule = await PluginRawMap[pluginName]();
        const PluginClass = pluginModule.default;

        if (!PluginClass) {
          throw new Error(`插件 ${pluginName} 没有默认导出`);
        }
        const pluginInstance = new PluginClass(option as any) as PluginMap[K];
        // 存储插件实例
        this.plugins[pluginName] = pluginInstance;

        return pluginName;
      });

      await Promise.all(pluginPromises);
    } catch (error) {
      console.error('[PluginManager]-插件加载失败:', error);
    } finally {
      this._emitEvent(PluginManager.EVENT_PLUGINS_LOADED, this.plugins);
    }
  }

  destroy(): void {
    Object.values(this.plugins).forEach((plugin) => {
      plugin.destroy();
    });
    this.plugins = {};
    this._removeEvents();
  }
}
